/*-------------------------------------------------------------------------
 *
 * pmsignal.h
 *	  后台进程与其子进程之间的信号例程
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/storage/pmsignal.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef PMSIGNAL_H
#define PMSIGNAL_H

#include <signal.h>

#ifdef HAVE_SYS_PRCTL_H
#include "sys/prctl.h"
#endif

#ifdef HAVE_SYS_PROCCTL_H
#include "sys/procctl.h"
#endif

/*
 * 向主进程发信号的原因。我们可以处理不同原因的同时信号。
 * 然而，如果同一个原因在短时间内被多次触发，主进程可能只会观察到
 * 一次通知。对于目前的用途，这没有问题。
 */
typedef enum
{
	PMSIGNAL_RECOVERY_STARTED,	/* 恢复已开始 */
	PMSIGNAL_BEGIN_HOT_STANDBY, /* 开始热备用 */
	PMSIGNAL_ROTATE_LOGFILE,	/* 发送 SIGUSR1 给 syslogger 以轮转日志文件 */
	PMSIGNAL_START_AUTOVAC_LAUNCHER,	/* 启动自动清理启动程序 */
	PMSIGNAL_START_AUTOVAC_WORKER,	/* 启动自动清理工作者 */
	PMSIGNAL_BACKGROUND_WORKER_CHANGE,	/* 后台工作者状态变化 */
	PMSIGNAL_START_WALRECEIVER, /* 启动 walreceiver */
	PMSIGNAL_ADVANCE_STATE_MACHINE, /* 推进主进程的状态机 */

	NUM_PMSIGNALS				/* 必须是枚举的最后一个值！ */
} PMSignalReason;

/*
 * 主进程为何会向其子进程发送 SIGQUIT 的原因。
 */
typedef enum
{
	PMQUIT_NOT_SENT = 0,		/* 主进程尚未发送 SIGQUIT */
	PMQUIT_FOR_CRASH,			/* 其他某个后端崩溃了 */
	PMQUIT_FOR_STOP				/* 指令要求立即停止 */
} QuitSignalReason;

/* PMSignalData 是一个不透明结构，细节仅在 pmsignal.c 内部已知 */
typedef struct PMSignalData PMSignalData;

/*
 * pmsignal.c 中的函数原型
 */
extern Size PMSignalShmemSize(void);
extern void PMSignalShmemInit(void);
extern void SendPostmasterSignal(PMSignalReason reason);
extern bool CheckPostmasterSignal(PMSignalReason reason);
extern void SetQuitSignalReason(QuitSignalReason reason);
extern QuitSignalReason GetQuitSignalReason(void);
extern int	AssignPostmasterChildSlot(void);
extern bool ReleasePostmasterChildSlot(int slot);
extern bool IsPostmasterChildWalSender(int slot);
extern void MarkPostmasterChildActive(void);
extern void MarkPostmasterChildInactive(void);
extern void MarkPostmasterChildWalSender(void);
extern bool PostmasterIsAliveInternal(void);
extern void PostmasterDeathSignalInit(void);


/*
 * 我们是否有办法在父进程死亡时请求信号？
 *
 * 如果有，pmsignal.c 将设置一个信号处理程序，当
 * 父进程死亡时设置一个标志。首先检查这个标志使得 PostmasterIsAlive() 
 * 在主进程活着的通常情况下更便宜。
 */
#if (defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_PDEATHSIG)) || \
	(defined(HAVE_SYS_PROCCTL_H) && defined(PROC_PDEATHSIG_CTL))
#define USE_POSTMASTER_DEATH_SIGNAL
#endif

#ifdef USE_POSTMASTER_DEATH_SIGNAL
extern PGDLLIMPORT volatile sig_atomic_t postmaster_possibly_dead;

static inline bool
PostmasterIsAlive(void)
{
	if (likely(!postmaster_possibly_dead))
		return true;
	return PostmasterIsAliveInternal();
}
#else
#define PostmasterIsAlive() PostmasterIsAliveInternal()
#endif

#endif							/* PMSIGNAL_H */
